package graphUtility.test3;

import java.awt.Point;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.util.LinkedList;
import javax.xml.transform.TransformerConfigurationException;
import org.jgrapht.Graph;
import org.jgrapht.alg.DijkstraShortestPath;
import org.jgrapht.ext.GmlExporter;
import org.jgrapht.ext.GraphMLExporter;
import org.jgrapht.ext.VisioExporter;
import org.jgrapht.graph.ListenableDirectedWeightedGraph;
import org.jgrapht.graph.ListenableUndirectedGraph;
import org.jgrapht.graph.SimpleGraph;
import org.jgrapht.graph.SimpleWeightedGraph;
import org.jgrapht.traverse.BreadthFirstIterator;
import org.jgrapht.traverse.DepthFirstIterator;
import org.xml.sax.SAXException;
import vacuumCleaner.Action;
import vacuumCleaner.Action.Type;
import vacuumCleaner.Agent;
import vacuumCleaner.Environment;
import vacuumCleaner.Floor;
import vacuumCleaner.Perception;
import vacuumCleaner.Square;
import sun.misc.Queue;

public class GraphFactory3 {

	private LinkedList<Action.Type> mossePossibili=new LinkedList<Action.Type>();
	private Graph<State3,MyEdge3> simpleGraph;
	private Environment environment;
	private Perception myAgentPerception;
	private LinkedList<Point> listaCoordDirtySquares;
	
	State3 start;
	State3 finish=null;
	
	int START=0, SOUTH=1, NORTH=2, WEST=3, EAST=4, SUCK=5, FINISH=6;
	State3 [] currentRoot={null,null,null,null,null,null,null};

	
	public GraphFactory3(Environment environment) {
		// TODO Auto-generated constructor stub
		simpleGraph=new SimpleWeightedGraph <State3,MyEdge3>(MyEdge3.class);
		this.environment=environment;
	}
	
	public void initBuildGraph() throws InterruptedException
	{
		listaCoordDirtySquares=getCoordinateDirtySquares();

		start=new State3("Start",new Point(environment.agent.x,environment.agent.y), listaCoordDirtySquares);
		simpleGraph.addVertex(start);
		currentRoot[START]=start;
		generateNewGraph(currentRoot);
		
	}
	
	public Graph<State3, MyEdge3> generateNewGraph(State3 [] currentRoot)
	{
		if(finish!=null)
			return simpleGraph;
		
		for(int i=1;i<currentRoot.length;i++)
		{
			if(canAddVertex(Type.NORTH,currentRoot[NORTH]))
			{
				LinkedList<Point> listaClonataNorth=(LinkedList<Point>)currentRoot[NORTH].getCoordinateMattonelleSporche().clone();
				State3 childNorth=new State3("North",new Point(currentRoot[NORTH].getAgentPosition().x-1,currentRoot[NORTH].getAgentPosition().y),listaClonataNorth);
				MyEdge3 currentEdge=new MyEdge3(currentRoot[NORTH], childNorth);
				if(simpleGraph.addVertex(childNorth))
					currentRoot[NORTH]=null;
				else
					currentRoot[NORTH]=childNorth;
				simpleGraph.addEdge(currentEdge.getSource(),currentEdge.getTarget(),currentEdge);
			}
			if(canAddVertex(Type.SOUTH,currentRoot[SOUTH]))
			{
				LinkedList<Point> listaClonataSouth=(LinkedList<Point>)currentRoot[SOUTH].getCoordinateMattonelleSporche().clone();
				State3 childSouth=new State3("South",new Point(currentRoot[SOUTH].getAgentPosition().x+1,currentRoot[SOUTH].getAgentPosition().y),listaClonataSouth);
				MyEdge3 currentEdge=new MyEdge3(currentRoot[SOUTH], childSouth);
				if(simpleGraph.addVertex(childSouth))
					currentRoot[SOUTH]=null;
				else
					currentRoot[SOUTH]=childSouth;
				simpleGraph.addEdge(currentEdge.getSource(),currentEdge.getTarget(),currentEdge);
			}
			if(canAddVertex(Type.WEST,currentRoot[WEST]))
			{
				LinkedList<Point> listaClonataWest=(LinkedList<Point>)currentRoot[WEST].getCoordinateMattonelleSporche().clone();
				State3 childWest=new State3("West",new Point(currentRoot[WEST].getAgentPosition().x,currentRoot[WEST].getAgentPosition().y-1),listaClonataWest);
				MyEdge3 currentEdge=new MyEdge3(currentRoot[WEST], childWest);
				if(simpleGraph.addVertex(childWest))
					currentRoot[WEST]=null;
				else
					currentRoot[WEST]=childWest;
				simpleGraph.addEdge(currentEdge.getSource(),currentEdge.getTarget(),currentEdge);
			}
			if(canAddVertex(Type.EAST,currentRoot[EAST]))
			{
				LinkedList<Point> listaClonataEast=(LinkedList<Point>)currentRoot[EAST].getCoordinateMattonelleSporche().clone();
				State3 childEast=new State3("East",new Point(currentRoot[EAST].getAgentPosition().x,currentRoot[EAST].getAgentPosition().y+1),listaClonataEast);
				MyEdge3 currentEdge=new MyEdge3(currentRoot[EAST], childEast);
				if(simpleGraph.addVertex(childEast))
					currentRoot[EAST]=null;
				else
					currentRoot[EAST]=childEast;
				simpleGraph.addEdge(currentEdge.getSource(),currentEdge.getTarget(),currentEdge);
			}
			if(canAddVertex(Type.SUCK,currentRoot[SUCK]) && !currentRoot[SUCK].getEtichetta().equals("Suck"))
			{
				LinkedList<Point> listaClonataSuck=(LinkedList<Point>)currentRoot[SUCK].getCoordinateMattonelleSporche().clone();
				listaClonataSuck.remove(new Point(currentRoot[SUCK].getAgentPosition().x,currentRoot[SUCK].getAgentPosition().y));
				State3 childSuck=new State3("Suck",new Point(currentRoot[SUCK].getAgentPosition().x,currentRoot[SUCK].getAgentPosition().y),listaClonataSuck);
				MyEdge3 currentEdge=new MyEdge3(currentRoot[SUCK], childSuck);
				if(simpleGraph.addVertex(childSuck))
					currentRoot[SUCK]=null;
				else
					currentRoot[SUCK]=childSuck;
				simpleGraph.addEdge(currentEdge.getSource(),currentEdge.getTarget(),currentEdge);
				
				if(listaClonataSuck.isEmpty())
				{
					finish=new State3("Finish",new Point(-1,-1),null);
					currentEdge=new MyEdge3(currentRoot[FINISH], finish);
					if(simpleGraph.addVertex(finish))
						currentRoot[FINISH]=null;
					else
						currentRoot[FINISH]=finish;
					simpleGraph.addEdge(currentEdge.getSource(),currentEdge.getTarget(),currentEdge);
						
					 System.out.println("Ho finito di generare il grafo! Numero nodi: "+simpleGraph.vertexSet().size());
				}
			}
		}
		return generateNewGraph(currentRoot);
	}
	
	public void addVertexEdge(State3 currentRoot, State3 child, int val)
	{
		MyEdge3 currentEdge=new MyEdge3(currentRoot, child);
		if(simpleGraph.addVertex(child))
			currentRoot=null;
		simpleGraph.addEdge(currentEdge.getSource(),currentEdge.getTarget(),currentEdge);
	}
	
	public void searchPath()
	{
		DijkstraShortestPath<State3, MyEdge3> dij=new DijkstraShortestPath<State3, MyEdge3>(simpleGraph, start, finish);
		
		for( MyEdge3 f :dij.getPathEdgeList())
		{
			//String mossa=getStringaMossa(f);
			//System.out.println("."+mossa+".");
			System.out.println(f.getTarget().getEtichetta());
			mossePossibili.add(StringToActionType(f.getTarget().getEtichetta()));
		}
			
	}
	
	
	public Action.Type StringToActionType(String mossa)
	{
		if(mossa.equals("South"))
			return Action.Type.SOUTH;
		else if(mossa.equals("North"))
				return Action.Type.NORTH;
		else if(mossa.equals("West"))
				return Action.Type.WEST;
		else if(mossa.equals("East"))
			return Action.Type.EAST;
		else if(mossa.equals("Suck"))
			return Action.Type.SUCK;
		else
			return Action.Type.NOOP;
	}
	
	public State3 getStart() {
		return start;
	}

	public void setStart(State3 start) {
		this.start = start;
	}

	boolean canAddVertex(Type type,State3 currentRoot)
	{
		
	
			if(currentRoot.getAgentPosition().x>0 && type==Type.NORTH &&
				myAgentPerception.floor.get(currentRoot.getAgentPosition().x-1,currentRoot.getAgentPosition().y)!=Square.Type.OBSTACLE)
				return true;
			else if(currentRoot.getAgentPosition().x<myAgentPerception.floor.length-1 && type==Type.SOUTH &&
					myAgentPerception.floor.get(currentRoot.getAgentPosition().x+1,currentRoot.getAgentPosition().y)!=Square.Type.OBSTACLE)
				return true;
			else if(currentRoot.getAgentPosition().y>0 && type==Type.WEST &&
					myAgentPerception.floor.get(currentRoot.getAgentPosition().x,currentRoot.getAgentPosition().y-1)!=Square.Type.OBSTACLE)
				return true;
			else if(currentRoot.getAgentPosition().y<myAgentPerception.floor.width-1 && type==Type.EAST &&
					myAgentPerception.floor.get(currentRoot.getAgentPosition().x,currentRoot.getAgentPosition().y+1)!=Square.Type.OBSTACLE)
				return true;
			else if(myAgentPerception.floor.get(currentRoot.getAgentPosition().x,currentRoot.getAgentPosition().y)==Square.Type.DIRTY && type==Type.SUCK)
				return true;
			
		return false;
	
	}

	public Graph<State3, MyEdge3> getSimpleGraph() {
		return simpleGraph;
	}

	public void setSimpleGraph(Graph<State3, MyEdge3> simpleGraph) {
		this.simpleGraph = simpleGraph;
	}


	public LinkedList<Action.Type> getMossePossibili() {
		return mossePossibili;
	}


	public void setMossePossibili(LinkedList<Action.Type> mossePossibili) {
		this.mossePossibili = mossePossibili;
	}
	public Perception getMyPerception() {
		return myAgentPerception;
	}
	public void setMyPerception(Perception myAgentPerception) {
		this.myAgentPerception = myAgentPerception;
	}
	
	public LinkedList<Point> getCoordinateDirtySquares()
	{
		LinkedList<Point> tempList=new LinkedList<Point>();
		for(int i=0;i<environment.floor.length;i++)
			for(int j=0;j<environment.floor.width;j++)
				if(environment.floor.get(i, j)==vacuumCleaner.Square.Type.DIRTY)
					tempList.add(new Point(i, j));

		return tempList;
	}
	
	
	
	
}
